package methodCallTreeGen;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 生成函数调用树的工具类
 */
public class MethodCallTreeGenUtil {
    /**
     * 从函数调用树中找到指定的targetTrace所在的TextNode，然后打印从root到TextNode的path
     * @param targetTrace 目标trace
     * @param rootMethodNode 函数调用树的根节点
     */
    public static void printRootToSpecifiedTraceNodePath(String targetTrace, MethodNode rootMethodNode) {
        // 定义一个list保存从root到textNode的path
        List<String> rootToSpecifiedTraceNodePathList = new ArrayList<>();
        // 从函数调用树中找到目标trace，并且将root到该 trace的MethodNode 的path保存到 rootToSpecifiedTraceNodePathList
        findSpecifiedTraceInMethodCallTree(targetTrace, rootMethodNode, rootToSpecifiedTraceNodePathList);

        if (rootToSpecifiedTraceNodePathList.size() == 0) {
            // 如果没有找到targetTrace
            System.err.println("没有找到目标trace");
        } else {
            System.out.println("root到目标trace的路径为:");
            for (String methodName : rootToSpecifiedTraceNodePathList) {
                System.out.println(methodName);
            }
        }
    }

    /**
     * 从函数调用树中找到目标trace，并且将root到该 trace的MethodNode 的path保存到 rootToSpecifiedTraceNodePathList
     *
     * @param targetTrace                      目标trace，一行String
     * @param methodNode                       当前查找的methodNode
     * @param rootToSpecifiedTraceNodePathList root到该 trace的MethodNode 的path
     */
    public static void findSpecifiedTraceInMethodCallTree(String targetTrace, MethodNode methodNode, List<String> rootToSpecifiedTraceNodePathList) {
        // 判断当前函数的所有TextNode里面有没有targetTrace
        for (Node node : methodNode.contentNodeList) {
            if (node.nodeType == NodeType.TEXT) {
                // 遍历当前函数下的每个TextNode，看看TextNode里面有没有targetTrace
                for (String traceLine : ((TextNode) node).tracesList) {
                    if (targetTrace.equals(traceLine)) {
                        // 找到了traceStr所在的位置
                        recordRootToSpecifiedNodePath((TextNode) node, rootToSpecifiedTraceNodePathList);
                        return;
                    }
                }
            }
        }
        // 如果当前MethodNode找不到targetTrace，找当前函数的子函数节点
        for (Node node : methodNode.contentNodeList) {
            if (node.nodeType == NodeType.METHOD) {
                findSpecifiedTraceInMethodCallTree(targetTrace, (MethodNode) node, rootToSpecifiedTraceNodePathList);
            }
        }
    }


    /**
     * 已经找到targetTrace在textNode中，将root到该textNode的路径记录下来到rootToSpecifiedNodePath
     *
     * @param textNode                targetTrace所在的textNode
     * @param rootToSpecifiedNodePath root到该textNode的路径
     */
    public static void recordRootToSpecifiedNodePath(TextNode textNode, List<String> rootToSpecifiedNodePath) {
        // 自当前TextNode向上遍历父节点
        MethodNode tempMethodNode = (MethodNode) textNode.parentNode;
        while (tempMethodNode != null) {
            rootToSpecifiedNodePath.add(tempMethodNode.methodName);
            tempMethodNode = (MethodNode) tempMethodNode.parentNode;
        }
        // 反转rootToSpecifiedNodePath表示从root到textNode的路径
        Collections.reverse(rootToSpecifiedNodePath);
    }
}

